package com.org.utils.conf;

import java.io.File;
import java.io.IOException;
import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;

/**
 * XML文件模式Configure
 * 
 * @author 
 */
public class ConfigureXml extends BaseConfigure implements Configure {

	/** JDOM文档对象 */
	private Document document;

	/**
	 * 构建器
	 * 
	 * @param fileName
	 * @throws IOException
	 */
	public ConfigureXml(String fileName) throws IOException {
		super(fileName);
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			document = builder.parse(new File(fileName));
			document.normalize();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new IOException(e.getMessage());
		}
	}

	/**
	 * 获取属性值
	 * 
	 * @param name
	 * @return String
	 */
	public synchronized String getProperty(String name) throws IOException {
		String result = null;
		Element rootNode = null;
		Node node = null;
		String value = (String) propertyCache.get(name); // 从Configure的缓存中取属性值
		if (value != null)
			return ConfigureMacro.getRealValue(value);
		String propName[] = parsePropertyName(name);
		if (propName.length == 0) {
			log.warn("Cannot find property: " + name);
			return null;
		}
		rootNode = document.getDocumentElement();
		node = rootNode.getParentNode();
		for (int i = 0; i < propName.length - 1; i++) {
			node = getChild(node, propName[i], 1);
			if (node == null) {
				log.warn("Cannot find property: " + name);
				return null;
			}
		}
		if (((Element) node).hasAttribute(propName[propName.length - 1])) {
			value = ((Element) node)
					.getAttribute(propName[propName.length - 1]);
		} else {
			node = getChild(node, propName[propName.length - 1]);
			if (node != null) {
				node = getChild(node, 3);
				do {
					if (node == null)
						break;
					if (node.getNodeValue() != null
							&& node.getNodeValue().trim().length() > 0) {
						value = node.getNodeValue();
						break;
					}
					node = getNextSibling(node, 3);
				} while (true);
			}
		}
		if (value == null) {
			log.warn("Cannot find property: " + name);
			return null;
		} else {
			value = value.trim();
			propertyCache.put(name, value);
			result = ConfigureMacro.getRealValue(value);
			return result;
		}
	}

	/**
	 * 获取子属性对象
	 * 
	 * @param parentPropertyName
	 * @return String []
	 */
	public synchronized String[] getChildrenPropertyNames(
			String parentPropertyName) throws IOException {
		String result[] = null;
		NamedNodeMap attributes = null;
		NodeList nodelist = null;
		String propName[] = parsePropertyName(parentPropertyName);
		List<Object> names = new ArrayList<Object>(5);
		Element rootNode = document.getDocumentElement();
		Node node = rootNode.getParentNode();
		for (int i = 0; i < propName.length; i++) {
			node = getChild(node, propName[i]);
			if (node == null) {
				result = new String[0];
				return result;
			}
		}
		attributes = node.getAttributes();
		if (attributes != null) {
			for (int i = 0; i < attributes.getLength(); i++)
				names.add(parentPropertyName + "."
						+ attributes.item(i).getNodeName());

		}
		nodelist = node.getChildNodes();
		if (nodelist != null) {
			for (int i = 0; i < nodelist.getLength(); i++)
				if (nodelist.item(i).getNodeType() == 1)
					names.add(parentPropertyName + "."
							+ nodelist.item(i).getNodeName());

		}
		result = names.toArray(new String[0]);
		return result;
	}

	/**
	 * 设置一个配置项目
	 * 
	 * @param name
	 * @param value
	 */
	public synchronized void setProperty(String name, String value)
			throws IOException {
		propertyCache.put(name, value);
		String propName[] = parsePropertyName(name);
		Element rootNode = document.getDocumentElement();
		Node node = rootNode.getParentNode();
		for (int i = 0; i < propName.length; i++) {
			node = getChild(node, propName[i]);
			if (node == null)
				continue;
			Attr attr = document.createAttribute(propName[i]);
			attr.setValue(value);
			if (node.getNodeType() == 1)
				((Element) node).setAttributeNode(attr);
		}

		saveProperties();
	}

	/**
	 * 删除一个配置项目
	 * 
	 * @param name
	 */
	public synchronized void deleteProperty(String name) throws IOException {
		propertyCache.remove(name);
		String propName[] = parsePropertyName(name);
		Element rootNode = document.getDocumentElement();
		Node node = rootNode.getParentNode();
		for (int i = 0; i < propName.length - 1; i++) {
			node = getChild(node, propName[i]);
			if (node == null)
				return;
		}

		if (node.getNodeType() != 1)
			return;
		if (((Element) node).hasAttribute(propName[propName.length - 1]))
			((Element) node).removeAttribute(propName[propName.length - 1]);
		Node cnode = getChild(node, propName[propName.length - 1]);
		if (cnode != null)
			node.removeChild(cnode);
		saveProperties();
	}

	/**
	 * 取得XML元素的子节点
	 * 
	 * @param node
	 * @param name
	 * @return Node
	 */
	private Node getChild(Node node, String name) {
		NodeList nodelist = node.getChildNodes();
		if (nodelist.getLength() == 0)
			return null;
		for (int i = 0; i < nodelist.getLength(); i++) {
			Node cnode = nodelist.item(i);
			if (cnode.getNodeName().equals(name))
				return cnode;
		}

		return null;
	}

	/**
	 * 取得XML元素的子节点
	 * 
	 * @param node
	 * @param name
	 * @param nodeType
	 * @return Node
	 */
	private Node getChild(Node node, String name, int nodeType) {
		NodeList nodelist = node.getChildNodes();
		if (nodelist.getLength() == 0)
			return null;
		for (int i = 0; i < nodelist.getLength(); i++) {
			Node cnode = nodelist.item(i);
			if (cnode.getNodeName().equals(name)
					&& cnode.getNodeType() == nodeType)
				return cnode;
		}

		return null;
	}

	/**
	 * 取得XML元素的子节点
	 * 
	 * @param node
	 * @param nodeType
	 * @return Node
	 */
	private Node getChild(Node node, int nodeType) {
		NodeList nodelist = node.getChildNodes();
		if (nodelist.getLength() == 0)
			return null;
		for (int i = 0; i < nodelist.getLength(); i++) {
			Node cnode = nodelist.item(i);
			if (cnode.getNodeType() == nodeType)
				return cnode;
		}

		return null;
	}

	/**
	 * 
	 * @param node
	 * @param nodeType
	 * @return Node
	 */
	private Node getNextSibling(Node node, int nodeType) {
		Node cnode;
		for (cnode = node; (cnode = cnode.getNextSibling()) != null;)
			if (cnode.getNodeType() == nodeType)
				return cnode;
		return cnode;
	}

	/**
	 * 保存配置
	 * 
	 * @throws IOException
	 */
	private synchronized void saveProperties() throws IOException {
		try {
			TransformerFactory tFactory = TransformerFactory.newInstance();
			Transformer transformer = tFactory.newTransformer();
			DOMSource source = new DOMSource(document);
			StreamResult result = new StreamResult(new File(configureFileName));
			transformer.transform(source, result);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new IOException(e.getMessage());
		}
	}

	public String[] getAllProperty() throws IOException {
		// TODO Auto-generated method stub
		return null;
	}

}
